#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Hamming_EDM.h"



using namespace std;

void Bytes_to_26_bits(unsigned char* byte_array, unsigned char* bits_block_array);
void bits_26_to_Byte(unsigned char* bits_block_array, unsigned char* byte_array);
void Block31_to_Bytes(unsigned char* block_31, unsigned char* bytes, int num_of_blocks);
void Bytes_to_Block31(unsigned char* block_31, unsigned char* bytes, int num_of_blocks);

int main(int argc, char* argv[])
{
	/*

	unsigned char x[13] = "123456789101";
	unsigned char y[13];
	x[12] = 'm';

	unsigned char block_31[16] = { 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e};
	unsigned char block_31_long[32] = { 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x2e,
										0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x0e, 0xaf, 0xff, 0xaf, 0x5e };
	unsigned char bytes_res[16];
	unsigned char bytes_res_long[31];
	unsigned char result[16];
	unsigned char result_block[16];
	unsigned char result_block_long[32];

	//Bytes_to_26_bits(x,result);
	//bits_26_to_Byte(result, y);
	//Block31_to_Bytes(block_31, bytes_res,4);
	Block31_to_Bytes(block_31_long, bytes_res_long, 8);
	Bytes_to_Block31(result_block_long, bytes_res_long,8);
	//Bytes_to_Block31(result_block, bytes_res,4);
	*/

	FILE * file_p;
	FILE * file_out_p;
	unsigned char buffer_bytes[26];
	unsigned char res_buffer_bytes[26];


	unsigned char hamming_blocks[32];

	unsigned char res_hamming_blocks[32];

	unsigned char bytes_to_send[31];
	unsigned char last_bytes_to_send[16];

	int NumOfCorrected = 0;


	file_p = fopen(argv[1],"rb");

	if (file_p == NULL)
	{
		cerr << "File open failed\n";
		exit(1);
	}
	file_out_p = fopen(argv[2], "wb");

	if (file_out_p == NULL)
	{
		cerr << "File 2 open failed\n";
		exit(1);
	}


	while (!feof(file_p))
	{
		size_t elements_read = fread(buffer_bytes, 1, 26, file_p);
		if ((elements_read < 26) && (!feof(file_p)))
		{
			cerr << "File read failed\n";
			exit(1);
		}
		else if (elements_read == 13) // we have reached to
		{							  //the last 13 bytes in the file
			Bytes_to_26_bits(buffer_bytes, hamming_blocks);
			//hamming_code_on 4 blocks
			//Hamming_EDM::encode_26To31(hamming_blocks);
			Block31_to_Bytes(hamming_blocks, last_bytes_to_send, 4);
			// need to add send function here
			Bytes_to_Block31(res_hamming_blocks, last_bytes_to_send, 4);
			// need to add decode 31 -> 26 4 blocks
			bits_26_to_Byte(res_hamming_blocks, res_buffer_bytes);
			size_t count = fwrite(res_buffer_bytes, 1, 13, file_out_p);
			if (count != 13)
			{
				cerr << "File write failed\n";
				exit(1);
			}
		}
		else if (elements_read == 26)
		{
			Bytes_to_26_bits(buffer_bytes, hamming_blocks);
			Bytes_to_26_bits(buffer_bytes+13, hamming_blocks+16);
			//hamming_code_on 8 blocks
			Hamming_EDM::encode_Blocks(hamming_blocks,8);
			Block31_to_Bytes(hamming_blocks, bytes_to_send, 8);
			// need to add send function here
			Bytes_to_Block31(res_hamming_blocks, bytes_to_send, 8);
			// need to add decode 31 -> 26 8 blocks
			cerr << "num of corrections" << Hamming_EDM::decode_Blocks(res_hamming_blocks, 8) << endl;
			bits_26_to_Byte(res_hamming_blocks, res_buffer_bytes);
			bits_26_to_Byte(res_hamming_blocks+16, res_buffer_bytes+13);
			size_t count = fwrite(res_buffer_bytes, 1, 26, file_out_p);
			if (count != 26)
			{
				cerr << "File write failed\n";
				exit(1);
			}


		}

	}

	fclose(file_p);
	fclose(file_out_p);

	

	return 0;

}

void Bytes_to_26_bits(unsigned char* byte_array, unsigned char* bits_block_array)
{
	
	bits_block_array[0] = byte_array[0];
	bits_block_array[1] = byte_array[1];
	bits_block_array[2] = byte_array[2];
	bits_block_array[3] = byte_array[3] & 0xc0;
	bits_block_array[4] = (byte_array[3] << 2) | (byte_array[4] >> 6);
	bits_block_array[5] = (byte_array[4] << 2) | (byte_array[5] >> 6);
	bits_block_array[6] = (byte_array[5] << 2) | (byte_array[6] >> 6);
	bits_block_array[7] = (byte_array[6] << 2) & 0xc0;
	bits_block_array[8] = (byte_array[6] << 4) | (byte_array[7] >> 4);
	bits_block_array[9] = (byte_array[7] << 4) | (byte_array[8] >> 4);
	bits_block_array[10] = (byte_array[8] << 4) | (byte_array[9] >> 4);
	bits_block_array[11] = (byte_array[9] << 4) & 0xc0;
	bits_block_array[12] = (byte_array[9] << 6) | (byte_array[10] >> 2);
	bits_block_array[13] = (byte_array[10] << 6) | (byte_array[11] >> 2);
	bits_block_array[14] = (byte_array[11] << 6) | (byte_array[12] >> 2);
	bits_block_array[15] = (byte_array[12] << 6);
}


void bits_26_to_Byte(unsigned char* bits_block_array, unsigned char* byte_array)
{
	byte_array[0] = bits_block_array[0];
	byte_array[1] = bits_block_array[1];
	byte_array[2] = bits_block_array[2];
	byte_array[3] = (bits_block_array[3] & 0xc0) | bits_block_array[4] >> 2;
	byte_array[4] = bits_block_array[4] << 6 | bits_block_array[5] >> 2;
	byte_array[5] = bits_block_array[5] << 6 | bits_block_array[6] >> 2;
	byte_array[6] = bits_block_array[6] << 6 | (bits_block_array[7] >> 2 & 0x30) | bits_block_array[8] >> 4;
	byte_array[7] = bits_block_array[8] << 4 | bits_block_array[9] >> 4;
	byte_array[8] = bits_block_array[9] << 4 | bits_block_array[10] >> 4;
	byte_array[9] = bits_block_array[10] << 4 | (bits_block_array[11] >> 4 & 0x0c) | bits_block_array[12] >> 6;
	byte_array[10] = bits_block_array[12] << 2 | bits_block_array[13] >> 6;
	byte_array[11] = bits_block_array[13] << 2 | bits_block_array[14] >> 6;
	byte_array[12] = bits_block_array[14] << 2 | bits_block_array[15] >> 6;
}
void Block31_to_Bytes(unsigned char* block_31, unsigned char* bytes, int num_of_blocks)
{
	bytes[0] = block_31[0];
	bytes[1] = block_31[1];
	bytes[2] = block_31[2];
	bytes[3] = block_31[3] | block_31[4] >> 7;
	bytes[4] = block_31[4] << 1 | block_31[5] >> 7;
	bytes[5] = block_31[5] << 1 | block_31[6] >> 7;
	bytes[6] = block_31[6] << 1 | block_31[7] >> 7;
	bytes[7] = block_31[7] << 1 | block_31[8] >> 6;
	bytes[8] = block_31[8] << 2 | block_31[9] >> 6;
	bytes[9] = block_31[9] << 2 | block_31[10] >> 6;
	bytes[10] = block_31[10] << 2 | block_31[11] >> 6;
	bytes[11] = block_31[11] << 2 | block_31[12] >> 5;
	bytes[12] = block_31[12] << 3 | block_31[13] >> 5;
	bytes[13] = block_31[13] << 3 | block_31[14] >> 5;
	bytes[14] = block_31[14] << 3 | block_31[15] >> 5;
	if (num_of_blocks == 4)
	{
		bytes[15] = block_31[15] << 3;
		return;
	}
	//else => num_of_block == 8
	bytes[15] = block_31[15] << 3 | block_31[16] >> 4;
	bytes[16] = block_31[16] << 4 | block_31[17] >> 4;
	bytes[17] = block_31[17] << 4 | block_31[18] >> 4;
	bytes[18] = block_31[18] << 4 | block_31[19] >> 4;
	bytes[19] = block_31[19] << 4 | block_31[20] >> 3;
	bytes[20] = block_31[20] << 5 | block_31[21] >> 3;
	bytes[21] = block_31[21] << 5 | block_31[22] >> 3;
	bytes[22] = block_31[22] << 5 | block_31[23] >> 3;
	bytes[23] = block_31[23] << 5 | block_31[24] >> 2;
	bytes[24] = block_31[24] << 6 | block_31[25] >> 2;
	bytes[25] = block_31[25] << 6 | block_31[26] >> 2;
	bytes[26] = block_31[26] << 6 | block_31[27] >> 2;
	bytes[27] = block_31[27] << 6 | block_31[28] >> 1;
	bytes[28] = block_31[28] << 7 | block_31[29] >> 1;
	bytes[29] = block_31[29] << 7 | block_31[30] >> 1;
	bytes[30] = block_31[30] << 7 | block_31[31] >> 1;

}


void Bytes_to_Block31(unsigned char* block_31, unsigned char* bytes, int num_of_blocks)
{
	block_31[0] = bytes[0];
	block_31[1] = bytes[1];
	block_31[2] = bytes[2];
	block_31[3] = bytes[3] & 0xfe;
	block_31[4] = bytes[3] << 7 | bytes[4] >> 1;
	block_31[5] = bytes[4] << 7 | bytes[5] >> 1;
	block_31[6] = bytes[5] << 7 | bytes[6] >> 1;
	block_31[7] = (bytes[6] << 7 | bytes[7] >> 1) & 0xfe;
	block_31[8] = bytes[7] << 6 | bytes[8] >> 2;
	block_31[9] = bytes[8] << 6 | bytes[9] >> 2;
	block_31[10] = bytes[9] << 6 | bytes[10] >> 2;
	block_31[11] = (bytes[10] << 6 | bytes[11] >> 2) & 0xfe;
	block_31[12] = bytes[11] << 5 | bytes[12] >> 3;
	block_31[13] = bytes[12] << 5 | bytes[13] >> 3;
	block_31[14] = bytes[13] << 5 | bytes[14] >> 3;
	block_31[15] = (bytes[14] << 5 | bytes[15] >> 3) & 0xfe;

	if (num_of_blocks == 4)
		return;

	block_31[16] = bytes[15] << 4 | bytes[16] >> 4;
	block_31[17] = bytes[16] << 4 | bytes[17] >> 4;
	block_31[18] = bytes[17] << 4 | bytes[18] >> 4;
	block_31[19] = (bytes[18] << 4 | bytes[19] >> 4) & 0xfe;
	block_31[20] = bytes[19] << 3 | bytes[20] >> 5;
	block_31[21] = bytes[20] << 3 | bytes[21] >> 5;
	block_31[22] = bytes[21] << 3 | bytes[22] >> 5;
	block_31[23] = (bytes[22] << 3 | bytes[23] >> 5) & 0xfe;
	block_31[24] = bytes[23] << 2 | bytes[24] >> 6;
	block_31[25] = bytes[24] << 2 | bytes[25] >> 6;
	block_31[26] = bytes[25] << 2 | bytes[26] >> 6;
	block_31[27] = (bytes[26] << 2 | bytes[27] >> 6) & 0xfe;
	block_31[28] = bytes[27] << 1 | bytes[28] >> 7;
	block_31[29] = bytes[28] << 1 | bytes[29] >> 7;
	block_31[30] = bytes[29] << 1 | bytes[30] >> 7;
	block_31[31] = bytes[30] << 1;
}